/*!
   \file

   \brief
      A scoped version of a OpenGL context on Windows which automatically cleans up after itself.

   © 2011 Mark W. Gabby II

   This file is part of Rock Hunter.

   Rock Hunter is free software: you can redistribute it and/or modify it under the terms of the
   GNU General Public License as published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

   Rock Hunter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
   even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along with Rock Hunter.
   If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScopedOpenGLContext.hpp"

#include "Systems/Platform/Platform.hpp"

#include "Systems/ErrorManager/ErrorManager.hpp"

extern HINSTANCE gInstanceHandle;

ScopedOpenGLContext::ScopedOpenGLContext()
{
   windowHandle = NULL;
   openGLContextHandle = NULL;
}

void ScopedOpenGLContext::Init( const uint32_t PixelFormatIndex )
{
   WNDCLASS WindowClass;
   WindowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
   WindowClass.lpfnWndProc = DefWindowProc;
   WindowClass.cbClsExtra = 0;
   WindowClass.cbWndExtra = 0;
   WindowClass.hInstance = gInstanceHandle;
   WindowClass.hIcon = NULL;
   WindowClass.hCursor = 0;
   WindowClass.hbrBackground = NULL;
   WindowClass.lpszMenuName = NULL;
   WindowClass.lpszClassName = "ScopedOpenGLContextWindowClass";

   // Register the window class
   RegisterClass( &WindowClass );
   UINT UIStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
   windowHandle = CreateWindow( WindowClass.lpszClassName, "ScopedOpenGLContextWindow", UIStyle,
                                0, 0, 1, 1, NULL, NULL, gInstanceHandle, NULL );
   HDC DeviceContext = GetDC();

   // Create a simple pixel format desired.
   PIXELFORMATDESCRIPTOR pfd = { 0 };
   pfd.nSize = sizeof( pfd );
   pfd.nVersion = 1;
   pfd.cColorBits = 32;
   pfd.cDepthBits = 24;
   pfd.cAccumBits = 0;
   pfd.cStencilBits = 8;
   pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;

   if ( PixelFormatIndex != kNull32 )
   {
      SetPixelFormat( DeviceContext, PixelFormatIndex, &pfd );
   }
   else
   {
      uint32_t tempPFindex = static_cast<uint32_t>( ChoosePixelFormat( DeviceContext, &pfd ) );
      SetPixelFormat( DeviceContext, tempPFindex, &pfd );
   }
   // Bind OpenGL to the window.
   openGLContextHandle = wglCreateContext( DeviceContext );
   wglMakeCurrent( DeviceContext, openGLContextHandle );

   ReleaseDC( DeviceContext );
}

ScopedOpenGLContext::~ScopedOpenGLContext()
{
   // Now we're done with the OpenGL rendering context,
   // so get rid of it.
   // If it's current, then
   if ( wglGetCurrentContext() == openGLContextHandle )
   {
      HDC DeviceContext = GetDC();
      // make it not current
      wglMakeCurrent( DeviceContext, NULL );
      ReleaseDC( DeviceContext );
   }
   wglDeleteContext( openGLContextHandle );

   // Cleanup: Destroy the window and unregister the window class
   DestroyWindow( windowHandle );
   UnregisterClass( "ScopedOpenGLContextWindowClass", gInstanceHandle );
}

bool ScopedOpenGLContext::IsCurrent()
{
   return wglGetCurrentContext() == openGLContextHandle;
}

void ScopedOpenGLContext::MakeCurrent()
{
   if ( IsCurrent() == false )
   {
      HDC DeviceContext = GetDC();
      wglMakeCurrent( DeviceContext, openGLContextHandle );
      ReleaseDC( DeviceContext );
   }
   else
   {
      // Do nothing, already current
   }
}

HDC ScopedOpenGLContext::GetDC()
{
   AssertError( windowHandle != NULL, "Can't get scoped context DC, did you call Init?" );

   return ::GetDC( windowHandle );
}
void ScopedOpenGLContext::ReleaseDC( HDC DeviceContext )
{
   AssertError( windowHandle != NULL, "Can't release scoped context DC, did you call Init?" );

   ::ReleaseDC( windowHandle, DeviceContext );
}

HGLRC ScopedOpenGLContext::GetHGLRC()
{
   AssertError( openGLContextHandle != NULL, "Can't get scoped context HGLRC, did you call Init?" );

   return openGLContextHandle;
}
